![]() Acrobat file (203K) |
![]() ClarisWorks 4 file (51K) |
![]() not available yet |
Technote 1061 | JULY 1996 |
This Technote describes the Open Firmware User Interface and Forth, the Open Firmware language. This Note addresses how to connect the target machine to a host machine for two machine mode. It explains how to use the interface to go between two and one machine mode. It also provides an explanation of the basics of Forth, an introduction to the device tree, and some debugging techniques.
This Technote is targeted at the expansion device designer and the driver writer for that device. The reader should have an understanding of Open Firmware as described by the IEEE 1275-1994 Specification, the PCI Local Bus Specification 2.0+, the PCI Bus Binding Specification 1.5, and Designing PCI Cards and Drivers for Power Macintosh Computers.
This purpose of this Technote is to supplement the sparse documentation covering Open Firmware on the Macintosh.
Nodes, which are also called packages, contain properties and methods. Properties are attributes that describe the hardware and driver. Methods do work much like subroutines or procedures. The hardware and software engineer can use the Open Firmware user interface to debug their device and driver, respectively. See Technote 1044, Understanding PCI Expansion Choices for Mac OS 8, Part III in the Open Firmware Technote Series, for details about properties and methods for various devices. You must be able to traverse the device tree to get to your node and then to edit and debug that node.
Forth is the human interface language to Open Firmware and the device tree. If you're a board designer, you'll want to directly read and write registers on your device, and, therefore, must be able to move throughout the device tree, create and delete words, etc. The driver writer has similar needs and must also build an FCode representation of the driver properties and methods. If the device contains a boot driver, that driver must be debugged using the Open Firmware user interface.
A boot driver is written in Forth, then tokenized into FCode and debugged from the interface. This form of driver is used during the earliest stages of the boot process before an operating system is available. Boot drivers are typically display, keyboard, network, and block, but are not limited to these.
The Open Firmware user interface, therefore, as specified by the IEEE1275-1994 Specification, is required to allow board designers and driver writers access to their hardware and software to build and debug their expansion device project. Let's see how that works.
Open Firmware, 1.0.5 To continue booting the MacOS type: BYETo continue booting from the default boot device type: BOOT ok 0 >
The O.K. means the interpeter is waiting for keyboard input. The 0 indicates the top of the stack.
0 > " pci2/@f" output \ the path must point to your display node 0 > " kbd" input
Auto-boot? is its name and if you set auto-boot? to false, you no longer have to hold down the Option-Command-O-F keys upon restart.
0 > printenv little-endian? false false real-mode? false false auto-boot? true true diag-switch? false false fcode-debug? false false oem-banner? false false oem-logo? false false use-nvramrc? true false real-base -1 -1 real-size 100000 100000 virt-base -1 -1 virt-size 100000 100000 load-base 4000 4000 pci-probe-list -1 -1 screen-#columns 64 64 screen-#rows 28 28 selftest-#megs 0 0 boot-device /AAPL,ROM /AAPL,ROM boot-file diag-device fd:diags fd:diags diag-file input-device ttya ttya output-device ttya ttya oem-banner oem-logo boot-command boot boot ok 0 >You are ready to use the interface and at this point and a few words about Forth are needed.
0 > 5 ok 1 > 7 ok 2 > + ok 1 > . C ok. . . But where is the correct answer, which is 12?
Setting Forth's Numeric Base
The C means 0xC for hexidecimal. The Open Firmware user interface defaults to a hexidecimal numeric-base. The radix can be hexidecimal, decimal, or octal and can be changed as follows:
hex | means interpet all input and output in hexidecimal. |
decimal | means interpet all input and output in decimal. |
octal | means interpet all input and output in octal. |
If you want to change only the next input or output character and then return to the existing numeric-base, use these words.
h# | means interpet the following number as hexadecimal. |
d# | means interpet the following number as decimal. |
o# | means interpet the following number as octal. |
Also, there is the .d and .h equivalent words for displaying.
To display the current base, output in decimal, enter:
0 > base @ .d 16k 0 >At this point, all the following numbers in this Technote will be decimal for convienence.
Try the above example again, but this time begin by changing the default to decimal, and your results will look like the following:
0 > decimal ok 0 > 5 ok 1 > 7 ok 2 > + ok 1 > . 12 ok 0 >Since Forth interpets a word using white space delimiters, we can type more than one word on a line as follows:
0 > 5 7 + . 12 ok 0 >
0 > 5 7 + .s 12 ok 1 >This shows us two things:
0 > 1 2 3 4 . 4 ok 3 > .s 1 2 3 ok 3 > . . . 3 2 1 ok 0 >1 then 2 then 3 then 4 were put onto the stack, and then the top item, 4, was displayed. <.> removed the 4 and displayed it. This made the stack depth go to 3. When <.s> was entered, the entire stack was displayed, but no item was removed. <.s> is very useful when debugging, since it can let you see what you actually entered onto the stack before executing a word.
0 > 1 2 3 4 ok 4 > bad-word bad-word, unknown word ok 0 >Since bad-word is not a word in the Forth dictionary, the interpeter cleared the entire stack. Usually, there are ways to return to a command when this occurs. Open Firmwares terminal emulator allows the use of the arrow keys to return to previous lines so that you may edit a line before trying the offending or unknown word.
0 > 1 2 3 4 depth .s 1 2 3 4 4 ok 5 > clear .s Empty ok 0 >Four numbers were placed on the stack and then the < depth > word was executed. As you might expect, this word determined how deep the stack was and then placed that number on the top of the stack. <.s> displayed the entire stack, including the result of < depth >. < clear > returned the stack depth to zero, as can be seen by its output (i.e., Empty) when displayed with the < .s > word.
+ ( nu1 nu2 -- sum )
depth ( -- u )
Now, let's look at the format of a stack notation. It begins with the < ( > led and followed by a white space, so it's a word. It informs the Forth enterpeter to ignore all characters until it sees the < ) > word, which does not need to be delimited by white spaces at the beginning and end of itself. The -- is a separator of the item on the stack before and after execution of a word. Item(s) to the left are on the stack before the word is executed and item(s) to the right are placed on the stack by the word.
So < + > then takes the two top most values off the stack, adds them, and returns the sum to the stack. Note that there can be many more values on the stack below the two topmost in this example. < depth > determines the number of values on the stack and places an unsigned number on the top of the stack.
0 > 1 2 3 4 ok 4 > dup ok 5 > .s 1 2 3 4 4 ok 5 >So < dup > duplicated the top item on the stack, which can be seen from entering the < .s > command.
Now enter the following:
5 > clear 1 2 3 2dup .s 1 2 3 2 3 ok 5 > 3dup .s 1 2 3 2 3 3 2 3 ok 8 >< clear > emptied the stack, 1 2 3 were entered, and then the 2 and 3 were duplicated using the < 2dup > word. The stack then produced 1 2 3 2 3 when < 3dup > was entered. At this point there were eight items on the stack.
Next, remove those items:
8 > drop .s 1 2 3 2 3 3 2 ok 7 > 2drop .s 1 2 3 2 3 ok 5 > 3drop .s 1 2 ok 2 > nip .s 2 ok 1 >You can drop one, two, or three items from the stack and you can nip it also as shown above. Here are the stack notations for your analysis of the previous example:
drop | ( x -- ) |
2drop | ( x1 x2 -- ) |
3drop | ( x1 x2 x3 -- ) |
nip | ( x1 x2 -- x2 ) |
clear |
( ... -- ) that is, < clear > removes all items as can be seen above. So the elipse means " all items ". |
The stack can also be rearranged, as follows:
0 > 1 2 3 4 .s 1 2 3 4 ok 4 > rot .s 1 3 4 2 ok 4 > -rot .s 1 2 3 4 ok 4 > swap .s 1 2 4 3 ok 4 > 2swap .s 4 3 1 2 ok 4 > clear ok 0 > rot ( x1 x2 x3 -- x2 x3 x1 ) rotated top three items -rot ( x1 x2 x3 -- x3 x1 x2 ) the other way swap ( x1 x2 -- x2 x1 ) 2swap ( x1 x2 x3 x4 -- x3 x4 x1 x2 )
Here is the display string word < ." >. When the interpeter sees this word, it inputs the following text string. When it sees < " > delimiter, it exits this mode and displays the string contained between the < ." >and the delimeter ". Here's an example.
0 > ." Hello world, I'm an example " Hello world, I'm an example ok 0 >What was entered was echoed. Here is the first word that did not take its operand from the stack. It took all characters until a < " > was seen. Here is the stack notation.
." ( [text<">] -- )
The [ ] pair says to take all text until a ". Can be confusing huh?
Here is the new or redefine word. It is called a colon definition and looks like this:
: + ." I don't do addition " ; Look at ." I don't do addition ". This is just a string. The < : > started the definition of a word called < + >that echoes the string and the < ; > ended the definition. Look at this example.
0 > 1 2 3 + .s 1 5 ok 2 > : + ( -- ) ." I don't do addition " ; ok 2 > + I don't do addition ok 2 > forget + ok 2 > + ok 1 > . 6 ok 0 >Can you tell what happened?
After the first addition the stack had a 5 on the top with a 1 below it. The new definition of < + > did nothing to the stack.
dev / ls< dev > is a word which opens a node in the tree and the particular node in this example is the root or /. This is a bus node for the AR bus (Apple RISC). < ls > lists all nodes, if any, under the present node. Let's see how that works:
0 > dev / ls 86746496: /PowerPC,604@0 86747184: /l2-cache@0,0 86749168: /chosen@0 86749472: /memory@0 86749800: /openprom@0 86749992: /AAPL,ROM@FFC00000 86750528: /options@0 86752280: /aliases@0 86752856: /packages@0 86752992: /deblocker@0,0 86755040: /disk-label@0,0 86756384: /obp-tftp@0,0 86765664: /mac-files@0,0 86767704: /mac-parts@0,0 86769592: /aix-boot@0,0 86770736: /fat-files@0,0 86776320: /iso-9660-files@0,0 86778696: /xcoff-loader@0,0 86781192: /terminal-emulator@0,0 86781344: /bandit@F2000000 86785936: /gc@10 86787016: /53c94@10000 86793296: /sd@0,0 86796416: /st@0,0 86799608: /mace@11000 86803312: /escc@13000 86803656: /ch-a@13020 86805368: /ch-b@13000 86807080: /awacs@14000 86807312: /swim3@15000 86811672: /via-cuda@16000 86814632: /adb@0,0 86814872: /keyboard@0,0 86816744: /mouse@1,0 86816920: /pram@0,0 86817096: /rtc@0,0 86818320: /power-mgt@0,0 86818608: /mesh@18000 86825624: /sd@0,0 86828744: /st@0,0 86832080: /nvram@1D000 86839664: /pci106b,1@B 86840136: /ATY,XCLAIM@D 86876008: /wayne.device@E 86878936: /wayne.device@F 86832488: /bandit@F4000000 86882192: /pci106b,1@B 86882664: /pci1234,5678@D 86883440: /TRUV,TARGA2000PCI@F 86837184: /hammerhead@F8000000 ok 0 >Take a close look at the tree and then go into your Developer Notes for the 9500 Macintosh. Notice that this resembles the block diagram on the 9500. It is the block diagram and more. Note that there are two nodes called bandit. One is /bandit@F2000000 and the other is /bandit@F4000000. These are full path names. One can deduce that full path names can contain address information, such as @F40000000, when the name is not unique, such as bandit. Bandit is the PCI bridge chip that has the AR bus as a parent and the PCI bus as a child. The the device tree listing is from my 9500 and contains debugging nodes called /wayne.device@E and /wayne.device@F.
Since we are at the root node, let's look at the pwd, .properties, and words words. Enter the following.
0 > pwd / ok 0 > .properties name device-tree model Power Macintosh compatible AAPL,9500 MacRISC AAPL,cpu-id 3900A69D #address-cells 00000001 #size-cells 00000001 clock-frequency 02FAF080 ok 0 > words dma-sync dma-map-out dma-map-in dma-free dma-alloc map-out map-in decode-unit close open ok 0 >< pwd > displays the full path name for the current node. In this case pwd displays the root node.
< .properties > listed all properties under this node (which is the AR bus). Note that although the < pwd > word listed the node name as/, its proper node name is device-tree. Look at the clock-frequency property, which is 0x02FAF080 (or 50MHz).
< words > listed the words ( methods ) implemented by this node. But what do these words do? Well, enter < see > and then the word you want to see, such as < open > .
0 > see open : open true ; ok 0 >So < open > just places the logical value of < true > onto the top of the stack.
Now let's look at one last maneuver - traversing the tree to another node. For this example, we'll look at the node called wayne at the top location in the tree.
0 > dev /bandit@F2000000/wayne.device ok 0 > pwd /bandit@F2000000/wayne.device@E ok 0 >
0 > devalias vci0 /chaos@F0000000 pci1 /bandit@F2000000 pci2 /bandit@F4000000 fd /bandit/gc/swim3 kbd /bandit/gc/via-cuda/adb/keyboard ttya /bandit/gc/escc/ch-a ttyb /bandit/gc/escc/ch-b enet /bandit/gc/mace scsi /bandit/gc/53c94 scsi-int /bandit/gc/mesh okLook at the second entry called pci1.
Now enter:
0 > dev pci1/@e ok 0 > pwd /bandit@F2000000/wayne.device@E ok 0 >Cool huh? pci1 is an alias of /bandit@F2000000.
Thanks to Monte Benaresh, Paul Freeburn, Ron Hochsprung, Jim Huffman, Pradeep
Kathail, Holly Knight, Tom Maremaa, and Samuel Yan.